package com.example.vue.sys.advice;

import com.alibaba.fastjson.JSONArray;
import com.auth0.jwt.JWT;
import com.example.vue.comm.domain.ResultData;
import com.example.vue.comm.util.IdUtil;
import com.example.vue.comm.util.StringUtil;
import com.example.vue.sys.domain.SysException;
import com.example.vue.sys.mapper.SysExceptionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 统一异常处理
 *
 * @author zhouxl
 * @DATE 2020/12/17
 * @descriptoin
 */
@ControllerAdvice
public class SysExceptionHandler {

    @Autowired
    private SysExceptionMapper sysExceptionMapper;

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResultData error(HttpServletRequest request, HttpServletResponse response, HandlerMethod method, Exception ex) {
        SysException sysException = sysException(request, response, method, ex);
        try {
            int row = sysExceptionMapper.addException(sysException);
        } catch (Exception e) {   // 执行存储sql错误,那么暂时做忽略处理
            System.out.println(e);
        }
        return ResultData.error("系统异常，异常信息[" + ex.getMessage() + "]");
    }

    private SysException sysException(HttpServletRequest request, HttpServletResponse response, HandlerMethod method, Exception ex) {
        String uuid = IdUtil.uuid();
        String exName = ex.getClass().getName();
        String exType = ex.getClass().getSimpleName();
        String exParams = request.getQueryString();

        SysException domain = new SysException();
        domain.setExNo(uuid);
        domain.setExName(exName);
        domain.setExType(exType);
        domain.setUrlParams(exParams);
        domain.setExStack(ex.getMessage());
        domain.setReqUrl(request.getRequestURI());
        String token = request.getHeader("token");
        if (StringUtil.isEmpty(token)) {
            domain.setAccountNo("");
        } else {
            String accountNo = JWT.decode(token).getClaim("accountNo").asString();
            domain.setAccountNo(accountNo);
        }
        domain.setCreateTime(new Date());
        dealExStack(method, domain, ex.getStackTrace());
        return domain;
    }

    /**
     * 处理异常栈信息
     */
    public void dealExStack(HandlerMethod method, SysException domain, StackTraceElement[] stackTrace) {
        // 发生异常的类名
        String className = method.getBeanType().getName();
        // 发生异常的方法名称
        String methodName = method.getMethod().getName();
        // 发生异常的代码位置
        int lineNumber = 0;
        for (StackTraceElement ele : stackTrace) {
            String name = className.substring(className.lastIndexOf(".") + 1);
            String fileName = ele.getFileName().replace(".java", "");
            if (name.equals(fileName)) {
                lineNumber = ele.getLineNumber();
                break;
            }
        }
        domain.setExClassName(className);
        domain.setExMethodName(methodName);
        domain.setExLocation(lineNumber);
        StringBuffer exStackBuilder = new StringBuffer();
        /**
         * 获取异常的栈信息
         */
//        for (StackTraceElement element : stackTrace) {
//            String jsonStr = JSONUtil.toJsonStr(element);
//            exStackBuilder.append(jsonStr);
//        }
        Object o = JSONArray.toJSON(stackTrace);
        /**
         * 获取异常的栈信息
         */
        domain.setExStack(o != null ? o.toString() : "{}");
    }

}
